home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1997
/
MacHack 1997.toast
/
Hacks
/
Hacks ’94
/
[√] Distribution Restricted!
/
Steve Sisak
/
TMFutures
/
Futures.c
< prev
next >
Wrap
Text File
|
1994-06-26
|
6KB
|
254 lines
/*
File: ThreadFuturesInternal.c
Contains: xxx put contents here xxx
Written by: xxx put writers here xxx
Copyright: © 1993 by Apple Computer, Inc., all rights reserved.
© 1994 by Steve Sisak, all rights reserved.
NOTE:
Need to check w/Dave Falkenberg at Apple for proper credit
for all previous writers of this code and proper copyright
before distribution
Change History (most recent first):
<1> 10/14/93 bsp first checked in
*/
#include "Futures.h"
#include <Threads.h>
#include <GestaltEqu.h>
pascal OSErr IsFutureBlock(AppleEvent* message);
pascal OSErr DoThreadBlock(AppleEvent* message);
pascal OSErr DoThreadUnblock(AppleEvent* message);
#define kAERefconAttribute 'refc'
#define kAENonexistantAttribute 'gag!'
#define kImmediateTimeout 0
#define kInitialThreadsInPool 5
#define kMinimumNumberOfFreeThreads 2
struct ThreadList
{
short numThreads;
ThreadID threads[1];
};
typedef struct ThreadList ThreadList, *ThreadListPtr, **ThreadListHdl;
#define sizeofThreadList(numthreads) (sizeof(ThreadList) + ((numthreads)-1)*sizeof(ThreadID))
pascal OSErr InitFutures(void)
{
OSErr theErr = noErr;
long aResponse;
theErr = Gestalt(gestaltThreadMgrAttr, &aResponse);
if (theErr)
return(theErr);
theErr = AEInstallSpecialHandler('blck', (ProcPtr) DoThreadBlock, false);
theErr = AEInstallSpecialHandler('unbk', (ProcPtr) DoThreadUnblock, false);
return(theErr);
}
pascal OSErr DoThreadBlock(AppleEvent* message)
{
OSErr theErr = noErr;
DescType actualType;
Size actualSize;
ThreadListHdl threadList;
ThreadID currentThread;
// Apparently the current thread needs to access some information, which
// is really a future. We need to see if there is already a list of threads
// blocked on this message. If there isn't, create an empty list. Add
// the current thread to the list. Sleep the current thread.
// We need to have a critical section because we are appending to the blocked
// queue list. If we get pre-empted during this code, that could really screw
// our list up. We probably won't get pre-empted, because we were called
// from the AE Manager. But its better to be safe than sorry.
ThreadBeginCritical();
theErr = GetCurrentThread(¤tThread);
theErr = AEGetAttributePtr(message, kAERefconAttribute,
typeLongInteger, &actualType, (Ptr) &threadList, sizeof(threadList), &actualSize);
if (theErr == errAEDescNotFound || !threadList)
{
// If we can't find a waiting thread list, then create one containing
// just ourself and put it back in the message
threadList = (ThreadListHdl) NewHandle(sizeofThreadList(1));
theErr = MemError();
(**threadList).numThreads = 1;
(**threadList).threads[0] = currentThread;
theErr = AEPutAttributePtr(message, kAERefconAttribute, typeLongInteger,
(Ptr) &threadList, sizeof(threadList));
theErr = noErr;
}
else
{
// Otherwise just append ourself onto the existing list
short numWaiting = (**threadList).numThreads;
SetHandleSize((Handle) threadList, sizeofThreadList(numWaiting+1));
theErr = MemError();
(**threadList).threads[numWaiting] = currentThread;
(**threadList).numThreads = ++numWaiting;
}
// If there was an error setting don't block (I think)
if (theErr == noErr)
theErr = SetThreadStateEndCritical(currentThread, kStoppedThreadState, kNoThreadID);
else
ThreadEndCritical();
return(theErr);
}
pascal OSErr DoThreadUnblock(AppleEvent* message)
{
OSErr theErr = noErr;
DescType actualType;
Size actualSize;
ThreadState blockedThreadState;
ThreadListHdl threadList;
// This message has just turned real. If there is a list of threads blocked
// because they tried to access the data, walk through the list of blocked
// threads waking and deallocating the list element as you go.
theErr = AEGetAttributePtr(message, kAERefconAttribute,
typeLongInteger, &actualType, (Ptr) &threadList, sizeof(threadList), &actualSize);
if (theErr == errAEDescNotFound || !threadList)
{
// It's possible that this unblocking handler will get called for ALL replies
// to apple events, not just futures. If that's the case, then getting
// the above error is not really an error. Clear it and just return.
theErr = noErr;
}
else
{
// We probably won't be pre-empted, but why take the chance? We need to make
// sure that while we are modifying the list, no one else comes in and changes
// anything.
ThreadBeginCritical();
{
ThreadID* nextThread = (**threadList).threads;
short numWaiting = (**threadList).numThreads;
while (--numWaiting >= 0)
{
ThreadID blockedThread = *nextThread++;
theErr = GetThreadState(blockedThread, &blockedThreadState);
if (blockedThreadState == kStoppedThreadState)
{
theErr = SetThreadState(blockedThread, kReadyThreadState, kNoThreadID);
}
}
// Now free the list handle (and take it out of the refCon just to be safe)
DisposeHandle((Handle) threadList);
threadList = nil;
theErr = AEPutAttributePtr(message, kAERefconAttribute, typeLongInteger,
(Ptr) &threadList, sizeof(threadList));
}
ThreadEndCritical();
}
return(theErr);
}
pascal OSErr BlockUntilReal(AppleEvent* message)
{
OSErr theErr = noErr;
AERecord nonExistentParameter;
theErr = AEGetParamDesc(message, kAENonexistantAttribute, typeAERecord,
&nonExistentParameter);
return(theErr);
}
pascal Boolean IsFuture(AppleEvent* message)
{
OSErr theErr = noErr;
ProcPtr oldBlockingProc;
Boolean isFuture = false;
theErr = AEGetSpecialHandler('blck', &oldBlockingProc, false);
if (theErr)
return(isFuture);
theErr = AEInstallSpecialHandler('blck', (ProcPtr) &IsFutureBlock, false);
if (theErr)
return(isFuture);
{
OSErr blockErr;
blockErr = BlockUntilReal(message);
theErr = AEInstallSpecialHandler('blck', oldBlockingProc, false);
if (blockErr == errAEReplyNotArrived)
isFuture = true;
}
return(isFuture);
}
pascal OSErr IsFutureBlock(AppleEvent* message)
{
#pragma unused(message);
return(noErr);
}
pascal OSErr Ask(AppleEvent* question, AppleEvent* answer)
{
OSErr theErr = noErr;
// Send the question with an immediate timeout.
theErr = AESend(question, answer, kAEWaitReply, kAENormalPriority,
kImmediateTimeout, nil, nil);
if (theErr == errAETimeout)
theErr = noErr;
return(theErr);
}